home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 03 - Advanced Graphics / Example 5 / sprite.c < prev    next >
Text File  |  1995-02-27  |  14KB  |  470 lines

  1. //
  2. //    File: sprite.c
  3. //
  4. //    This file contains the routines to draw the sprites
  5. //
  6. //    2/19/95 -- Created by Mick
  7. //
  8.  
  9. // include files
  10.  
  11. #include "global.h"
  12.  
  13. #include "sprite.h"
  14.  
  15. #include "main.h"
  16.  
  17. // defines for this file
  18.  
  19. #define kEndShapeToken                    0L                // the end of shape maker
  20. #define kLineStartToken                    1L                // the line start marker
  21. #define kDrawPixelsToken            2L                // the draw run marker
  22. #define kSkipPixelsToken                3L                // the skip pixels marker
  23.  
  24. // global function declarations
  25.  
  26. tSpriteInfo *loadSprite( signed short inSpriteResID );
  27. void disposeSprite( tSpriteInfo *inSpriteInfo );
  28. void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap );
  29. void endSpriteDraw( void );
  30. void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere );
  31.  
  32. // global data owned by this file
  33.  
  34. // local function declarations
  35.  
  36. static void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
  37. static void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect );
  38.  
  39. // static data
  40.  
  41. Rect sClipRect;                                                                // the rectangle to clip to
  42. PixMapHandle sDestPixMap;                        // where we are going to draw this data
  43. unsigned char *sBaseAddr;                    // the base address of the pixmap
  44. unsigned long sRowBytes;                        // the row bytes of the pixmap
  45.  
  46. // functions
  47.  
  48. //
  49. //    loadSprite -
  50. //
  51. //    Loads/allocates all the data for a sprite.
  52. //
  53.  
  54. tSpriteInfo *loadSprite( signed short inSpriteResID )
  55. {
  56.     tSpriteInfo *newSprite;            // the new sprite data
  57.     
  58.     // create the sprite info record
  59.     newSprite = ( tSpriteInfo * )NewPtr( sizeof( tSpriteInfo ) );
  60.     
  61.     // load the sprite
  62.     newSprite->fSpriteData = GetResource( kSpriteResType, inSpriteResID );
  63.     HNoPurge( newSprite->fSpriteData );
  64.     if ( newSprite->fSpriteData == ( Handle )kNil )
  65.         {
  66.             // if it did not load, drop into the debugger -- real programs would have error checking
  67.             Debugger();
  68.         }
  69.     
  70.     // copy its bounds rect
  71.     newSprite->fSpriteRect = **( ( Rect ** )( newSprite->fSpriteData ) );
  72.     
  73.     // return the new sprite!
  74.     return newSprite;
  75. }
  76.  
  77.  
  78. //
  79. //    disposeSprite -
  80. //
  81. //    Disposes/releases all the memory used in a sprite
  82. //
  83.  
  84. void disposeSprite( tSpriteInfo *inSpriteInfo )
  85. {
  86.     // dump the sprite resource
  87.     ReleaseResource( inSpriteInfo->fSpriteData );
  88.     
  89.     // free the structure
  90.     DisposePtr( ( Ptr )inSpriteInfo );
  91. }
  92.  
  93.  
  94. //
  95. //    startSpriteDraw -
  96. //
  97. //    Prepare the sprite draw. Assumes that the port is set to the destination port.
  98. //
  99.  
  100. void startSpriteDraw( Rect *inClipRect, PixMapHandle inDestPixMap )
  101. {
  102.     // set the clip region to be the passed in rect
  103.     sClipRect = *inClipRect;
  104.     
  105.     // save the pix map info (so we can use it)
  106.     sDestPixMap = inDestPixMap;
  107.  
  108.     // get info from the pix map
  109.     sBaseAddr = ( unsigned char * )GetPixBaseAddr( sDestPixMap );
  110.     sRowBytes = ( *sDestPixMap )->rowBytes & 0x3fff;
  111. }
  112.  
  113.  
  114. //
  115. //    endSpriteDraw -
  116. //
  117. //    End the sprite draw sequence.
  118. //
  119.  
  120. void endSpriteDraw( void )
  121. {
  122. }
  123.  
  124.  
  125. //
  126. //    drawSprite -
  127. //
  128. //    Draw the sprite in the port.
  129. //
  130.  
  131. void drawSprite( tSpriteInfo *inSpriteInfo, Point inWhere )
  132. {
  133.     Rect destRect;        // where we want to draw the sprite
  134.     
  135.     // calculate the destination rect
  136.     destRect = inSpriteInfo->fSpriteRect;
  137.     OffsetRect( &destRect, inWhere.h, inWhere.v );
  138.     
  139.     // determine if the spite needs to be drawn at all
  140.     if( destRect.top >= sClipRect.bottom || destRect.bottom <= sClipRect.top ||
  141.             destRect.left >= sClipRect.right || destRect.right <= sClipRect.left )
  142.         {
  143.             // no need to draw, goodbye
  144.             return;
  145.         }
  146.     
  147.     // determine if the sprite will be clipped
  148.     if ( destRect.top < sClipRect.top || destRect.bottom > sClipRect.bottom ||
  149.             destRect.left < sClipRect.left || destRect.right > sClipRect.right )
  150.         {
  151.             // handle the clipped case
  152.             renderSpriteClipped( inSpriteInfo, &destRect );
  153.         }
  154.     else
  155.         {
  156.             // handle the unclipped case
  157.             renderSpriteUnclipped( inSpriteInfo, &destRect );
  158.         }
  159. }
  160.  
  161.  
  162. //
  163. //    renderSpriteClipped -
  164. //
  165. //    Draw the spite, deal with clipping.
  166. //
  167.  
  168. void renderSpriteClipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
  169. {
  170.     Rect clipRect;                                                                    // the rect that defines the clipped shape
  171.     unsigned char *rowStart;                        // the pointer to the start of this row
  172.     unsigned char *srcPtr;                                // the current position in the sprite data
  173.     unsigned char *destPtr;                            // the current position in the destination pixmap
  174.     unsigned long miscCounter;                    // a counter for various purposes
  175.     unsigned long extraCounter;                // a counter for right clippling purposes ( how much extra was there? )
  176.     unsigned long tokenOp;                                    // the op code from the token
  177.     unsigned long tokenData;                            // the data from the token
  178.     unsigned char exitFlag;                                // should we exit from the loop?
  179.     unsigned long yCount;                                    // how many lines down in the shape are we?
  180.     unsigned long xCount;                                    // where are we in this line?
  181.     
  182.     // create a clipped rect in the coordinates of the sprite
  183.     clipRect.left = inDestRect->left < sClipRect.left ? sClipRect.left - inDestRect->left : 0;
  184.     clipRect.right = inDestRect->right > sClipRect.right ? sClipRect.right - inDestRect->left : inDestRect->right - inDestRect->left;
  185.     clipRect.top = inDestRect->top < sClipRect.top ? sClipRect.top - inDestRect->top : 0;
  186.     clipRect.bottom = inDestRect->bottom > sClipRect.bottom ? sClipRect.bottom - inDestRect->top : inDestRect->bottom - inDestRect->top;
  187.  
  188.     // set up the counters
  189.     yCount = 0;
  190.  
  191.     // determine characteristics about the pixmap
  192.     rowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
  193.     
  194.     // move to the right place in the shape ( just past the size rect )
  195.     srcPtr = ( unsigned char * )( ( *( inSpriteInfo->fSpriteData ) ) + sizeof( Rect ) );
  196.     
  197.     // loop until we are done
  198.     exitFlag = kFalse;
  199.     while( !exitFlag )
  200.         {
  201.             // get a token
  202.             tokenOp = ( *( ( unsigned long * )srcPtr ) ) >> 24;
  203.             tokenData = ( *( ( unsigned long * )srcPtr ) ) & 0x00ffffff;
  204.             srcPtr += sizeof( unsigned long );
  205.             
  206.             // depending on the token
  207.             switch( tokenOp )
  208.                 {
  209.                     case kDrawPixelsToken:
  210.                         miscCounter = tokenData;
  211.                         extraCounter = 0;
  212.                         
  213.                         // if we need to, clip to the left
  214.                         if( xCount < clipRect.left )
  215.                             {
  216.                                 // if this run does not appear at all, don't draw it
  217.                                 if ( miscCounter < clipRect.left - xCount )
  218.                                     {
  219.                                         destPtr += miscCounter;
  220.                                         srcPtr += miscCounter;
  221.                                         srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
  222.                                         xCount += miscCounter;
  223.                                         break;
  224.                                     }
  225.                                 else
  226.                                     {
  227.                                         // if it does, skip to where we can draw
  228.                                         miscCounter -= clipRect.left - xCount;
  229.                                         destPtr += clipRect.left - xCount;
  230.                                         srcPtr += clipRect.left - xCount;
  231.                                         xCount += clipRect.left - xCount;
  232.                                     }
  233.                             }
  234.                         
  235.                         // if we need to, clip to the right
  236.                         if ( xCount + miscCounter > clipRect.right )
  237.                             {
  238.                                 // if this run does not appear at all, skip it
  239.                                 if ( xCount > clipRect.right )
  240.                                     {
  241.                                         destPtr += miscCounter;
  242.                                         srcPtr += miscCounter;
  243.                                         srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
  244.                                         xCount += miscCounter;
  245.                                         break;
  246.                                     }
  247.                                 else
  248.                                     {
  249.                                         // if it does, setup to draw what we can
  250.                                         extraCounter = miscCounter;
  251.                                         miscCounter -= ( xCount + miscCounter ) - clipRect.right;
  252.                                         extraCounter -= miscCounter;
  253.                                     }
  254.                             }
  255.                         
  256.                         // adjust xCount for the run
  257.                         xCount += miscCounter;
  258.                         
  259.                         // move data in the biggest chunks we can find
  260.  #ifdef powerc
  261.                          // move in doubles while we can
  262.                         while( miscCounter >= sizeof( double ) )
  263.                             {
  264.                                 *( ( double * )destPtr ) = *( ( double * )srcPtr );
  265.                                 destPtr += sizeof( double );
  266.                                 srcPtr += sizeof( double );
  267.                                 miscCounter -= sizeof( double );
  268.                             }
  269.                         
  270.                         // move a long if we can
  271.                         if ( miscCounter >= sizeof( unsigned long ) )
  272.                             {
  273.                                 *( ( unsigned long * )destPtr ) = *( ( unsigned long  * )srcPtr );
  274.                                 destPtr += sizeof( unsigned long  );
  275.                                 srcPtr += sizeof( unsigned long  );
  276.                                 miscCounter -= sizeof( unsigned long  );
  277.                             }
  278. #else
  279.                         // move in longs while we can
  280.                         while( miscCounter >= sizeof( unsigned long ) )
  281.                             {
  282.                                 *( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
  283.                                 destPtr += sizeof( unsigned long );
  284.                                 srcPtr += sizeof( unsigned long );
  285.                                 miscCounter -= sizeof( unsigned long );
  286.                             }
  287. #endif                        
  288.                                                 
  289.                         // move a short if we can
  290.                         if ( miscCounter >= sizeof( unsigned short ) )
  291.                             {
  292.                                 *( ( unsigned short * )destPtr ) = *( ( unsigned short  * )srcPtr );
  293.                                 destPtr += sizeof( unsigned short  );
  294.                                 srcPtr += sizeof( unsigned short  );
  295.                                 miscCounter -= sizeof( unsigned short  );
  296.                             }
  297.  
  298.                         // move a char if we can
  299.                         if ( miscCounter >= sizeof( unsigned char ) )
  300.                             {
  301.                                 *( ( unsigned char  * )destPtr ) = *( ( unsigned char  * )srcPtr );
  302.                                 destPtr += sizeof( unsigned char  );
  303.                                 srcPtr += sizeof( unsigned char  );
  304.                                 miscCounter -= sizeof( unsigned char );
  305.                             }
  306.                         
  307.                         // adjust for right clipping
  308.                         destPtr += extraCounter;
  309.                         srcPtr += extraCounter;
  310.                         xCount += extraCounter;
  311.                         
  312.                         // adjust for the padding
  313.                         srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
  314.                         break;
  315.                         
  316.                     case kSkipPixelsToken:
  317.                         destPtr += tokenData;
  318.                         xCount += tokenData;
  319.                         break;
  320.                         
  321.                     case kLineStartToken:
  322.                         // if this line is above the clip rect, skip to the next line
  323.                         if( yCount < clipRect.top )
  324.                             {
  325.                                 srcPtr += tokenData;
  326.                             }
  327.  
  328.                         // set up the destination pointer
  329.                         destPtr = rowStart;
  330.                         rowStart += sRowBytes;
  331.                         
  332.                         // move the yCounter
  333.                         yCount++;
  334.                         
  335.                         // reset the xCounter
  336.                         xCount = 0;
  337.                         
  338.                         // if we have hit the bottom clip, exit the loop
  339.                         if ( yCount > clipRect.bottom )
  340.                             {
  341.                                 exitFlag = kTrue;
  342.                             }
  343.                         break;
  344.                         
  345.                     case kEndShapeToken:
  346.                         // signal a loop exit
  347.                         exitFlag = kTrue;
  348.                         break;
  349.                         
  350.                     default:
  351.                         // we should never get here
  352.                         Debugger();
  353.                         break;
  354.                 }
  355.         }
  356. }
  357.  
  358.  
  359. //
  360. //    renderSpriteUnclipped -
  361. //
  362. //    Draw the sprite, no clipping needed
  363. //
  364.  
  365. void renderSpriteUnclipped( tSpriteInfo *inSpriteInfo, Rect *inDestRect )
  366. {
  367.     unsigned char *rowStart;                // the pointer to the start of this row
  368.     unsigned char *srcPtr;                        // the current position in the sprite data
  369.     unsigned char *destPtr;                    // the current position in the destination pixmap
  370.     unsigned long miscCounter;            // a counter for various purposes
  371.     unsigned long tokenOp;                            // the op code from the token
  372.     unsigned long tokenData;                    // the data from the token
  373.     unsigned char exitFlag;                        // should we exit from the loop?
  374.     
  375.     // determine characteristics about the pixmap
  376.     rowStart = sBaseAddr + inDestRect->top * sRowBytes + inDestRect->left;
  377.     
  378.     // move to the right place in the shape ( just past the size rect )
  379.     srcPtr = ( unsigned char * )( ( *( inSpriteInfo->fSpriteData ) ) + sizeof( Rect ) );
  380.     
  381.     // loop until we are done
  382.     exitFlag = kFalse;
  383.     while( !exitFlag )
  384.         {
  385.             // get a token
  386.             tokenOp = ( *( ( unsigned long * )srcPtr ) ) >> 24;
  387.             tokenData = ( *( ( unsigned long * )srcPtr ) ) & 0x00ffffff;
  388.             srcPtr += sizeof( unsigned long );
  389.             
  390.             // depending on the token
  391.             switch( tokenOp )
  392.                 {
  393.                     case kDrawPixelsToken:
  394.                         miscCounter = tokenData;
  395.                         
  396.                         // move data in the biggest chunks we can find
  397.  #ifdef powerc
  398.                          // move in doubles while we can
  399.                         while( miscCounter >= sizeof( double ) )
  400.                             {
  401.                                 *( ( double * )destPtr ) = *( ( double * )srcPtr );
  402.                                 destPtr += sizeof( double );
  403.                                 srcPtr += sizeof( double );
  404.                                 miscCounter -= sizeof( double );
  405.                             }
  406.                         
  407.                         // move a long if we can
  408.                         if ( miscCounter >= sizeof( unsigned long ) )
  409.                             {
  410.                                 *( ( unsigned long * )destPtr ) = *( ( unsigned long  * )srcPtr );
  411.                                 destPtr += sizeof( unsigned long  );
  412.                                 srcPtr += sizeof( unsigned long  );
  413.                                 miscCounter -= sizeof( unsigned long  );
  414.                             }
  415. #else
  416.                         // move in longs while we can
  417.                         while( miscCounter >= sizeof( unsigned long ) )
  418.                             {
  419.                                 *( ( unsigned long * )destPtr ) = *( ( unsigned long * )srcPtr );
  420.                                 destPtr += sizeof( unsigned long );
  421.                                 srcPtr += sizeof( unsigned long );
  422.                                 miscCounter -= sizeof( unsigned long );
  423.                             }
  424. #endif                        
  425.                                                 
  426.                         // move a short if we can
  427.                         if ( miscCounter >= sizeof( unsigned short ) )
  428.                             {
  429.                                 *( ( unsigned short * )destPtr ) = *( ( unsigned short  * )srcPtr );
  430.                                 destPtr += sizeof( unsigned short  );
  431.                                 srcPtr += sizeof( unsigned short  );
  432.                                 miscCounter -= sizeof( unsigned short  );
  433.                             }
  434.  
  435.                         // move a char if we can
  436.                         if ( miscCounter >= sizeof( unsigned char ) )
  437.                             {
  438.                                 *( ( unsigned char  * )destPtr ) = *( ( unsigned char  * )srcPtr );
  439.                                 destPtr += sizeof( unsigned char  );
  440.                                 srcPtr += sizeof( unsigned char  );
  441.                                 miscCounter -= sizeof( unsigned char );
  442.                             }
  443.  
  444.                         // adjust for the padding
  445.                         srcPtr += ( ( tokenData & 3L ) == 0 ) ? 0 : ( 4 - ( tokenData & 3L ) );
  446.                         break;
  447.                         
  448.                     case kSkipPixelsToken:
  449.                         destPtr += tokenData;
  450.                         break;
  451.                         
  452.                     case kLineStartToken:
  453.                         // set up the destination pointer
  454.                         destPtr = rowStart;
  455.                         rowStart += sRowBytes;
  456.                         break;
  457.                         
  458.                     case kEndShapeToken:
  459.                         // signal a loop exit
  460.                         exitFlag = kTrue;
  461.                         break;
  462.                         
  463.                     default:
  464.                         // we should never get here
  465.                         Debugger();
  466.                         break;
  467.                 }
  468.         }
  469. }
  470.